﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Collections.Concurrent;

namespace C0710_ChatRoom_Server
{
    /// <summary>
    /// 与客户端的 连接通信类(包含了一个 与客户端 通信的 套接字，和线程)
    /// </summary>
    public class ConnectionClient
    {
        Socket sokMsg;
        DGShowMsg dgShowMsg;//负责 向主窗体文本框显示消息的方法委托
        DGShowMsg dgRemoveConnection;// 负责 从主窗体 中移除 当前连接
        Thread threadMsg;
        ConcurrentDictionary<string, ConnectionClient> dictConn;
        #region 构造函数
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sokMsg">通信套接字</param>
        /// <param name="dgShowMsg">向主窗体文本框显示消息的方法委托</param>
        public ConnectionClient(Socket sokMsg, ConcurrentDictionary<string, ConnectionClient> dictClient, DGShowMsg dgShowMsg, DGShowMsg dgRemoveConnection)
        {
            this.sokMsg = sokMsg;
            this.dgShowMsg = dgShowMsg;
            this.dgRemoveConnection = dgRemoveConnection;
            this.dictConn = dictClient;
            this.threadMsg = new Thread(RecMsg);
            this.threadMsg.IsBackground = true;
            this.threadMsg.Start();
        } 
        #endregion

        bool isRec = true;
        #region 02负责监听客户端发送来的消息
        void RecMsg()
        {
            while (isRec)
            {
                try
                {
                    byte[] arrMsg = new byte[1024 * 1024 * 2];
                    //接收 对应 客户端发来的消息
                    int length = sokMsg.Receive(arrMsg);
                    //将接收到的消息数组里真实消息转成字符串
                    string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, length);
                    //通过委托 显示消息到 窗体的文本框
                    dgShowMsg(strMsg);
                    SendTo(strMsg);
                }
                catch (Exception ex)
                {
                    isRec = false;
                    //从主窗体中 移除 下拉框中对应的客户端选择项，同时 移除 集合中对应的 ConnectionClient对象
                    dgRemoveConnection(sokMsg.RemoteEndPoint.ToString());
                }
            }
        }
        #endregion

        #region 向特定客户端转发消息
        public void SendTo(string strMsg)
        {
            var msgArr = strMsg.Split('|');
            string endPoint = msgArr[0];
            strMsg = msgArr[1];
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
            byte[] arrMsgFinal = new byte[arrMsg.Length + 1];

            arrMsgFinal[0] = 0;//设置 数据标识位等于0，代表 发送的是 文字
            arrMsg.CopyTo(arrMsgFinal, 1);


            var sock = this.dictConn[endPoint];
            //sokMsg.Send(arrMsgFinal);
            sock.sokMsg.Send(arrMsgFinal);
        }
        #endregion

        #region 03向客户端发送消息
        /// <summary>
        /// 向客户端发送消息
        /// </summary>
        /// <param name="strMsg"></param>
        public void Send(string strMsg)
        {
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
            byte[] arrMsgFinal = new byte[arrMsg.Length+1];

            arrMsgFinal[0] = 0;//设置 数据标识位等于0，代表 发送的是 文字
            arrMsg.CopyTo(arrMsgFinal, 1);

            sokMsg.Send(arrMsgFinal);
        } 
        #endregion


        #region 06关闭与客户端连接
        /// <summary>
        /// 关闭与客户端连接
        /// </summary>
        public void CloseConnection()
        {
            isRec = false;
        } 
        #endregion
    }
}
